import bottle
import json

from bottle import abort, get, post, put
from wrapt import synchronized

import service
import dao

DEFAULT_REVIEWER_ID = None


def get_default_reviewer_id():
    global DEFAULT_REVIEWER_ID
    if DEFAULT_REVIEWER_ID is None:
        reviewer = service.get_session().query(dao.User).filter_by(name="shengnan").first()
        if reviewer is None:
            return None
        DEFAULT_REVIEWER_ID = reviewer.id
    return DEFAULT_REVIEWER_ID


# todo handle unexpected exceptions

@get("/users/<user_id>")
def query_users(user_id):
    try:
        user_id_int = int(user_id)
        user: dao.User = service.get_session().query(dao.User).filter_by(id=user_id_int).first()
        if user is None:
            return abort(404, "The user id does not exists")
        return {"id": user.id, "name": user.name, "role": user.role.value}
    except ValueError:
        pass


@post("/users")
def create_user():
    input_name = bottle.request.params['name']
    if len(input_name) == 0:
        return abort(400, "Empty user name")
    status_code = 200

    @synchronized
    def lock_create_user(user_name):
        db_user = service.get_session().query(dao.User).filter_by(name=user_name).first()
        if db_user is None:
            status_code = 201
            db_user = service.get_session().add(dao.User(name=user_name))
            service.get_session().commit()
        return db_user

    user_ins = lock_create_user(input_name)
    return bottle.HTTPResponse(status=status_code, body=json.dumps({"id", user_ins.id}))


# create code review tasks
@post("/tasks/cr_tasks")
def create_code_review_task():
    url = bottle.request.params['review_url']
    if len(url) == 0:
        return abort(400, "The review url is empty")
    if service.task_exsits_by_url(url):
        return abort(400, "The review task exists")
    submitter_id = bottle.request.params['submit_user_id']
    if not service.user_exists(int(submitter_id)):
        return abort(400, "The user does not exists")
    remark = bottle.request.params.get('remark', "")
    reviewer_id = get_default_reviewer_id()

    task = dao.CodeReviewTask(submit_user_id=submitter_id, proceess_user_id=reviewer_id, revieiw_url=url, remark=remark)
    service.get_session().add(task)
    service.get_session().commit()


def cr_task_to_json(task: dao.CodeReviewTask):
    return {
        "id": task.id,
        "submit_user_id": task.submit_user_id,
        "process_user_id": task.process_user_id,
        "review_url": task.review_url,
        "priority": task.priority.value,
        "status": task.status.value,
        "remark": task.remark,
        "created_time": task.created_time,
        "last_update_time": task.last_updated_time
    }


# page_index: starts from 0, default 0
# page_size: default 50
@get("/tasks/cr_tasks")
def query_cr_tasks():
    page_size = int(bottle.request.params.get("page_size", 50))
    page_index = int(bottle.request.params.get("page_index", 0))
    if page_size < 0:
        page_size = 50
    if page_index < 0:
        page_index = 0
    tasks = service.get_session().query(dao.CodeReviewTask).order_by(dao.CodeReviewTask.created_time.desc()).\
            limit(page_size).offset(page_index).all()
    return {
        "cr_tasks": [cr_task_to_json(task) for task in tasks]
    }


@put("/tasks/cr_tasks/<task_id>/status")
def change_cr_task_status(task_id):
    pass


@put("/tasks/cr_tasks/<task_id>/priority")
def change_cr_task_priority(task_id):
    pass